"""
Description: Train emotion classification model

"""
# 这个文件的作用是训练模型，通过CNN训练fer2013



from keras.callbacks import CSVLogger, ModelCheckpoint, EarlyStopping #用于将训练过程中的指标（如准确率和损失）记录到CSV文件中。
from keras.callbacks import ReduceLROnPlateau 
from keras.preprocessing.image import ImageDataGenerator
from load_and_process import load_fer2013
# 除了Fer2013以外，还有CK+数据集 使用MATLAB对这些数据进行预处理和训练 最后调用已经训练好的模型对图像中存在的人脸目标进行表情识别分类
from load_and_process import preprocess_input
from models.cnn import mini_XCEPTION
from sklearn.model_selection import train_test_split

# parameters
batch_size = 32 #训练时每个批次的大小。
num_epochs = 10000 #训练的epoch数
input_shape = (48, 48, 1) #输入图像的尺寸和通道数。
validation_split = .2 #将数据集中的一部分用于验证集的比例。
verbose = 1 #在训练过程中输出信息的详细程度。0为不输出，1为输出进度条，2为输出每个epoch的信息。
num_classes = 7 #数据集中的情感类别数。
patience = 50 #在准确率不再提高时等待的epoch数。如果在这个epoch数内准确率仍未提高，则停止训练。
base_path = 'models/'

# data generator
data_generator = ImageDataGenerator(
                        featurewise_center=False,
                        featurewise_std_normalization=False, #不进行归一化和标准化操作
                        rotation_range=10,
                        width_shift_range=0.1,
                        height_shift_range=0.1, #表示随机旋转、水平和垂直平移的范围
                        zoom_range=.1,
                        horizontal_flip=True)
                        # ImageDataGenerator  对图像数据进行增强，包括随机旋转、平移、缩放和翻转等操作，以扩充训练集的规模和多样性

# model parameters/compilation
model = mini_XCEPTION(input_shape, num_classes)
model.compile(optimizer='adam', loss='categorical_crossentropy',
              metrics=['accuracy'])
# mini_XCEPTION 是一个卷积神经网络模型，其主要结构包括卷积层、深度可分离卷积层、批量归一化层和全局平均池化层等。
# 这个模型使用 Adam 优化器、categorical_crossentropy 损失函数和 accuracy 指标进行编译

model.summary()
    # callbacks
log_file_path = base_path + '_emotion_training.log'
# 一系列回调函数，包括 CSVLogger、EarlyStopping、ReduceLROnPlateau 
# 和 ModelCheckpoint 等，用于在训练过程中保存模型、记录日志和监控模型性能等
# 回调函数是指在某些事件发生时，系统会自动调用指定的函数进行处理 ， 回调函数通常作为参数传递给其他函数或类，以便在特定的条件下被调用
csv_logger = CSVLogger(log_file_path, append=False)
early_stop = EarlyStopping('val_loss', patience=patience)
reduce_lr = ReduceLROnPlateau('val_loss', factor=0.1,
                                  patience=int(patience/4), verbose=1)
trained_models_path = base_path + '_mini_XCEPTION'
model_names = trained_models_path + '.{epoch:02d}-{val_acc:.2f}.hdf5'
model_checkpoint = ModelCheckpoint(model_names, 'val_loss', verbose=1,
                                                    save_best_only=True)
callbacks = [model_checkpoint, csv_logger, early_stop, reduce_lr]

# loading dataset加载 FER2013 数据集，并对图像进行预处理操作，包括归一化和标准化等
faces, emotions = load_fer2013()
faces = preprocess_input(faces)
num_samples, num_classes = emotions.shape
# 使用 train_test_split 函数将数据集划分为训练集和测试集，并将数据输入到 model.fit_generator 中进行训练。
# 在训练过程中，使用 data_generator.flow 生成批次的数据进行训练，
# 同时使用前面定义的回调函数来监控和优化模型性能
xtrain, xtest,ytrain,ytest = train_test_split(faces, emotions,test_size=0.2,shuffle=True)
model.fit_generator(data_generator.flow(xtrain, ytrain, #生成批次的数据进行训练
                                            batch_size),
                        steps_per_epoch=len(xtrain) / batch_size, #表示每个周期需要训练的批次数量
                        epochs=num_epochs, verbose=1, callbacks=callbacks, #epochs 参数表示训练周期数，callbacks 参数表示需要使用的回调函数
                        validation_data=(xtest,ytest))
